﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Interpreter
{
	internal static class Util
	{
		// For string collections that are in the format of ([piece length][piece data])+ where piece length is an 8-digit hex value
		public static string[] BreakString(string largeString, int expectedSize)
		{
			List<string> pieces = new List<string>();
			int index = 0;
			while (index < largeString.Length)
			{
				string pieceLengthString = largeString.Substring(index, 8);
				int pieceLength = Util.ConvertFromHex(pieceLengthString);
				index += 8;
				string value = largeString.Substring(index, pieceLength);
				index += pieceLength;
				pieces.Add(value);
			}

			if (index != largeString.Length || pieces.Count != expectedSize)
			{
				throw new Exception("Corrupted file.");
			}

			return pieces.ToArray();
		}

		public static string ConvertFromHexString(string hexString)
		{
			char[] output = new char[hexString.Length / 2];
			for (int i = 0; i < output.Length; ++i)
			{
				output[i] = (char)(byte)ConvertFromHex(hexString.Substring(i * 2, 2));
			}

			return string.Join("", output);
		}

		public static int ToInt(string stringValue)
		{
			int value;
			if (!int.TryParse(stringValue, out value))
			{
				throw new Exception("Corrupted file.");
			}
			return value;
		}

		public static void Verify(bool condition)
		{
			if (!condition)
			{
				throw new Exception("Corrupted header.");
			}
		}

		public static int[][] DoubleSplit(string value, char rowDelimiter, char columnDelimiter, bool useDummyFor0)
		{
			List<int[]> output = new List<int[]>();
			if (useDummyFor0)
			{
				output.Add(null);
			}

			foreach (string row in SmartSplit(value, rowDelimiter))
			{
				output.Add(SplitToInt(row, columnDelimiter));
			}

			return output.ToArray();
		}

		public static int[] SplitToInt(string value, char delimiter)
		{
			List<int> output = new List<int>();
			foreach (string item in SmartSplit(value, delimiter))
			{
				output.Add(ConvertFromHex(item));
			}
			return output.ToArray();
		}

		public static string[] SmartSplit(string value, char delimiter)
		{
			if (value.Length == 0)
			{
				return new string[0];
			}

			return value.Split(delimiter);
		}

		private const int a_offset = 'a' - 10;
		private const int A_offset = 'A' - 10;

		public static int ConvertFromHex(string hex)
		{
			int output = 0;
			int sign = 1;
			int start = 0;
			int length = hex.Length;
			if (hex[0] == '-')
			{
				sign = -1;
				start = 1;
			}
			char c;
			for (int i = start; i < length; ++i)
			{
				c = hex[i];
				if (c >= '0' && c <= '9')
				{
					output = (output << 4) + (c - '0');
				}
				else if (c >= 'a' && c <= 'f')
				{
					output = (output << 4) + (c - a_offset);
				}
				else if (c >= 'A' && c <= 'F')
				{
					output = (output << 4) + (c - A_offset);
				}
				else
				{
					throw new Exception("Invalid value.");
				}
			}

			return output * sign;
		}

		public static string GetTypeStringFromValue(Value value)
		{
			switch (value.Type)
			{
				case Value.TYPE_NULL: return "null";
				case Value.TYPE_BOOLEAN: return "boolean";
				case Value.TYPE_INTEGER: return "integer";
				case Value.TYPE_FLOAT: return "float";
				case Value.TYPE_STRING: return "string";
				case Value.TYPE_INSTANCE: return "class instance";
				case Value.TYPE_CLASS: return "class definition";
				case Value.TYPE_LIST: return "list";
				case Value.TYPE_DOT_POINTER: return "field";
				default: throw new NotImplementedException();
			}
		}

		public static string GetInvalidOperatorExceptionMessage(string op, Value left, Value right)
		{
			return "The " + op + " operator is not defined for types: " + GetTypeStringFromValue(left) + " and " + GetTypeStringFromValue(right);
		}
	}
}
